//
//  UIImage+BlurGlass.m
//  BackgroundBlur
//
//  Created by wd on 15/7/14.
//  Copyright (c) 2015年 wd. All rights reserved.
//

#import "UIImage+BlurGlass.h"
#import <Accelerate/Accelerate.h>

@implementation UIImage (BlurGlass)

/**
 *  默认模糊的图片效果
 *
 *  @return 模糊的图片
 */
- (UIImage *)imageWithBlurGlass
{
    return [self imageWithLightAlpha:0.1 radius:10.0 colorSaturationFactor:1.0];
}

/**
 *  自定义 图片 模糊效果
 *
 *  @param alpha                 0~1   0为白, 1为深灰色
 *  @param radius                模糊半径， radius越大图像越模糊
 *  @param colorSaturationFactor 色彩饱和度 无彩色的黑白灰定为0，最鲜艳定为9
 *
 *  @return 模糊图像image
 */
- (UIImage *)imageWithLightAlpha:(CGFloat)alpha radius:(CGFloat)radius colorSaturationFactor:(CGFloat)colorSaturationFactor
{
    UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:alpha];
    return [self imageBluredWithRadius:radius tintColor:tintColor saturationFactor:colorSaturationFactor maskImage:nil];
}

// 毛玻璃效果
- (UIImage *)imageBluredWithRadius:(CGFloat)blurRadius tintColor:(UIColor*)tintColor saturationFactor:(CGFloat)saturationFactor maskImage:(UIImage *)maskImage
{
    CGRect imageRect = {CGPointZero, self.size};
    UIImage *bluredImage = self;

    BOOL hasBlur = blurRadius > __FLT_EPSILON__;
    BOOL hasSatusrationChange = fabs(saturationFactor - 1.0) > __FLT_EPSILON__;
    
    if (hasBlur || hasSatusrationChange) {
        UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, [[UIScreen mainScreen] scale]);
        CGContextRef effectInContext = UIGraphicsGetCurrentContext();
        CGContextScaleCTM(effectInContext, 1.0, -1.0);
        CGContextTranslateCTM(effectInContext, 0, -imageRect.size.height);
        CGContextDrawImage(effectInContext, imageRect, bluredImage.CGImage);
        
        vImage_Buffer effectInBuffer;
        effectInBuffer.data = CGBitmapContextGetData(effectInContext);
        effectInBuffer.width = CGBitmapContextGetWidth(effectInContext);
        effectInBuffer.height = CGBitmapContextGetHeight(effectInContext);
        effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
        
        UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, [[UIScreen mainScreen]scale]);
        CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
        vImage_Buffer effectOutBuffer;
        effectOutBuffer.data = CGBitmapContextGetData(effectOutContext);
        effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext);
        effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext);
        effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
        
        if (hasBlur) {
            CGFloat inputRadius = blurRadius * [[UIScreen mainScreen]scale];
            uint32_t radius = floor(inputRadius * 3.0 * sqrt(2 * M_PI) / 4 + 0.5);
            if (radius % 2 != 1) {
                radius += 1;  // force radius to be odd so that the three box-blur methodology works.
            }
            vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
            vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
            vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
        }
        
//        BOOL effectImageBufferAreSwapped = NO;
        
        if (hasSatusrationChange) {
            CGFloat s = saturationFactor;
            CGFloat floatPointSaturationMatrix[] = {
                0.0722 + 0.9278 * s,  0.0722 - 0.0722 * s,  0.0722 - 0.0722 * s,  0,
                0.7152 - 0.7152 * s,  0.7152 + 0.2848 * s,  0.7152 - 0.7152 * s,  0,
                0.2126 - 0.2126 * s,  0.2126 - 0.2126 * s,  0.2126 + 0.7873 * s,  0,
                0,                    0,                    0,  1,
            };
            const int32_t divisor = 256;
            NSUInteger matrixSize = sizeof(floatPointSaturationMatrix)/sizeof(floatPointSaturationMatrix[0]);
            int16_t saturationMatrix[matrixSize];
            for (int i = 0; i < matrixSize; i++) {
                saturationMatrix[i] = (int16_t)roundf(floatPointSaturationMatrix[i] * divisor);
            }
            
            if (hasBlur) {
                vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
//                effectImageBufferAreSwapped = YES;
            } else {
                vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
            }
        }
        
//        if (!effectImageBufferAreSwapped) {
            bluredImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
//        }
    }
    
    // 开启上下文 用于输出图像
    UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, [[UIScreen mainScreen]scale]);
    CGContextRef outputContext = UIGraphicsGetCurrentContext();
    CGContextScaleCTM(outputContext, 1.0, -1.0);
    CGContextTranslateCTM(outputContext, 0, -imageRect.size.height);
    
    // 开始画底图
    CGContextDrawImage(outputContext, imageRect, bluredImage.CGImage);
    
    // 模糊效果
    if (hasBlur) {
        CGContextSaveGState(outputContext);
        if (maskImage) {
            CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
        }
        CGContextDrawImage(outputContext, imageRect, bluredImage.CGImage);
        CGContextRestoreGState(outputContext);
    }
    
    // 添加颜色渲染
    if (tintColor) {
        CGContextSaveGState(outputContext);
        CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
        CGContextFillRect(outputContext, imageRect);
        CGContextRestoreGState(outputContext);
    }
    
    // 输出 模糊图片并关闭上下文
    UIImage *outputBluredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return outputBluredImage;
}

@end
